local skel = fk.CreateSkill {
  name = "emo__qicui",
}

Fk:loadTranslationTable{
  ["emo__qicui"] = "奇淬",
  [":emo__qicui"] = "你可以重铸一张牌以发动一个牌面上有此牌名的装备效果，若不为【杀】，你可以移动场上一张牌。"..
  "<br><font color='red'>部分装备技能无法发动</font>",

  ["#emo__qicui-move"] = "奇淬：可以移动场上一张牌",
  ["#emo__qicui-recast"] = "奇淬：可以重铸一张牌，发动牌面上有此牌名的装备效果",
  ["#emo__qicui-invoke"] = "奇淬：可以重铸一张【%arg】牌面上含有的牌，以发动此装备",
  ["#emo__qicui-active"] = "奇淬：请发动装备技能【%arg】",
  ["#emo__qicui-select"] = "奇淬：选择你要发动的装备技能，重铸1张牌面上有的牌名",

  ["$emo__qicui1"] = "鬼斧神工，天赐神匠。",
  ["$emo__qicui2"] = "玲珑剔透，需得神手。",
}

--- 牌面信息含有此牌名的牌
---@param id integer @ 要筛选的牌
---@param equip string @ 装备牌牌名
---@return boolean
local function hasCardInfo(id, equip)
  local card = Fk:getCardById(id)
  if card.name == equip then return true end
  local nameStr = Fk:translate(card.name  , "zh_CN")
  local trueName = Fk:translate(card.trueName, "zh_CN")
  if string.find(nameStr, trueName, 1, true) then -- 防止真名和牌名不同的情况
    nameStr = trueName
  end
  local str = Fk:translate(":" .. equip, "zh_CN") -- 装备牌牌面信息
  local pattern = "装备技能"
  local startIndex, endIndex = string.find(str, pattern)
  if startIndex then
    str = string.sub(str, endIndex + 1)
  end
  return string.find(str, nameStr, 1, true) ~= nil
end

--- 获取此装备牌牌名描述含有的牌
---@param player Player @ 角色
---@param equip string @ 要发动的装备名
---@return integer[]
local function getMatchCard(player, equip)
  return table.filter(player:getCardIds("he"), function (id)
    return hasCardInfo(id, equip)
  end)
end

--- 移动场上一张牌
---@param player ServerPlayer
local moveInBoard = function (player)
  if player.dead then return end
  local room = player.room
  if #room:canMoveCardInBoard() == 0 then return end
  local tos = room:askToChooseToMoveCardInBoard(player, {
    skill_name = skel.name, cancelable = true, prompt = "#emo__qicui-move"
  })
  if #tos == 2 then
    room:askToMoveCardInBoard(player, {
      skill_name = skel.name, target_one = tos[1], target_two = tos[2]
    })
  end
end

--- 能否于出牌阶段空闲时使用一个转化技
--- 此函数包含了使用次数判断（次数不够丈八不亮）
---@param skill ViewAsSkill
---@param player Player
local function canUseViewAsAtPlay(skill, player)
  if skill:enabledAtPlay(player) then
    if skill.pattern == nil then return false end
    -- 没有pattern，说明是泛转化，直接不给过
    local exp = Exppattern:Parse(skill.pattern)
    local cnames = {}
    for _, m in ipairs(exp.matchers) do
      if m.name then
        table.insertTable(cnames, m.name)
      end
      if m.trueName then
        table.insertTable(cnames, m.trueName)
      end
    end

    for _, n in ipairs(cnames) do
      local c = Fk:cloneCard(n)
      c:setVSPattern(skill.name, player, nil)
      if c.skill:canUse(player, c) and not player:prohibitUse(c) then return true end
    end
  end
  return false
end

--- 可选的装备技能
---@param player Player
local canUseChoices = function (player)
  local choices = {}
  local active = table.map(Fk:currentRoom():getBanner("emo__qicui_active") or {}, Util.Name2SkillMapper)---@type ActiveSkill[]
  local viewas = table.map(Fk:currentRoom():getBanner("emo__qicui_viewas") or {}, Util.Name2SkillMapper)---@type ViewAsSkill[]
  if Fk.currentResponsePattern == nil then
    for _, skill in ipairs(active) do
      local equip = skill:getSkeleton().attached_equip
      if equip and #getMatchCard(player, equip) > 0 then
        if skill:canUse(player) then
          table.insert(choices, equip)
        end
      end
    end
    for _, skill in ipairs(viewas) do
      local equip = skill:getSkeleton().attached_equip
      if equip and #getMatchCard(player, equip) > 0 then
        if canUseViewAsAtPlay(skill, player) then
          table.insert(choices, equip)
        end
      end
    end
  end
  return choices
end

skel:addEffect("viewas", {
  anim_type = "offensive",
  prompt = "#emo__qicui-select",
  pattern = ".",
  mute_card = true,
  interaction = function(self, player)
    local choices = canUseChoices(player)
    if #choices > 0 then
      return UI.ComboBox { choices = choices }
    end
  end,
  card_filter = function (self, player, to_select, selected)
    local equip = self.interaction.data
    if #selected == 0 and type(equip) == "string" then
      return hasCardInfo(to_select, equip)
    end
  end,
  target_filter = Util.FalseFunc,
  card_num = 1,
  target_num = 0,
  feasible = function (self, player, selected, selected_cards)
    return #selected_cards == 1
  end,
  on_use = function (self, room, skillUse, _, params)
    local cards = skillUse.cards
    local notSlash = Fk:getCardById(cards[1]).trueName ~= "slash"
    local player = skillUse.from
    local equip = skillUse.interaction_data
    if not equip then return end
    local equipCard = Fk:cloneCard(equip) ---@type EquipCard
    local skill = equipCard.equip_skill ---@type ActiveSkill|ViewAsSkill
    if not skill then return end
    room:recastCard(cards, player, skel.name)
    if player.dead then return end
    if params == nil then -- 出牌阶段空闲时
      local _ , dat = room:askToUseActiveSkill(player, {
        prompt = "#emo__qicui-active:::" .. skill.name, skill_name = skill.name,
      })
      if dat then
        local use_spec = {
          from = player,
          cards = dat.cards,
          tos = dat.targets,
          interaction_data = dat.interaction,
        }
        -- use_data.cost_data = skill:onCost(player, use_spec)
        local use_data = SkillUseData:new(use_spec)
        if skill:isInstanceOf(ActiveSkill) then
          room:useSkill(player, skill, function()
            skill:onUse(room, use_data)
          end, use_data)
        elseif skill:isInstanceOf(ViewAsSkill) then
          local useResult
          local c = skill:viewAs(player, use_spec.cards)
          room:useSkill(player, skill, function()
            useResult = skill:onUse(room, use_data, c, params) or ""
            if type(useResult) == "table" then
              player.room:useCard(useResult)
              skill:afterUse(player, useResult)
              useResult = nil
            end
          end, use_data)
        end
      end
    end
    if player.dead then return end
    if notSlash then
      room.logic:getCurrentEvent():addExitFunc(function() -- 偷懒大王
        moveInBoard(player)
      end)
    end
  end,
  view_as = function ()
    return nil
  end,
  enabled_at_play = function(self, player)
    return #canUseChoices(player) > 0
  end,
  enabled_at_response = Util.FalseFunc, -- 偷懒，响应牌太难写了
})


local all_events = { ---@type TriggerEvent[]
  -- use
  fk.TargetSpecifying, fk.TargetConfirming, fk.TargetSpecified, fk.TargetConfirmed,
  fk.PreCardEffect, fk.BeforeCardEffect, fk.CardEffecting, fk.CardEffectFinished, fk.CardEffectCancelledOut,
  fk.PreCardRespond, fk.CardResponding,fk.CardRespondFinished,
  fk.PreCardUse, fk.AfterCardUseDeclared, fk.AfterCardTargetDeclared, fk.CardUsing, fk.BeforeCardUseEffect, fk.CardUseFinished,
  -- damage
  fk.DamageCaused, fk.DetermineDamageCaused, fk.DamageInflicted, fk.DetermineDamageInflicted, fk.Damage, fk.Damaged, fk.DamageFinished,
  -- hp
  fk.PreHpLost, fk.HpLost, fk.PreHpRecover, fk.HpRecover, fk.BeforeMaxHpChanged, fk.MaxHpChanged,
  -- death
  fk.EnterDying, fk.AfterDying, fk.AskForPeaches, fk.AskForPeachesDone,
  fk.Death, fk.BeforeGameOverJudge, fk.GameOverJudge, fk.Deathed, fk.BuryVictim,
  -- misc
  fk.AskForCardUse, fk.AskForCardResponse, -- 八卦
}

--- 获取当前事件可以发动的装备技能
---@param event TriggerEvent
---@return TriggerSkill[]
local getSkillsForEvent = function (event)
  local map = Fk:currentRoom():getBanner("emo__qicui_trigger")
  if map == nil then return {} end
  local index = table.indexOf(all_events, event.class)
  if map[index] then -- 记录的是可发动技能的字符串表，转为技能表
    return table.map(map[index], function (s)
      return Fk.skills[s]
    end)
  end
  return {}
end

--- 检测此装备技能是否能发出
---@param skill TriggerSkill @ 装备技能，注意，不一定是主技能
---@param player ServerPlayer
---@return boolean?
local checkTriggerable = function (skill, event, target, player, data)
  if player:hasSkill(skill, true, true) then return end-- 如果我已有此装备，那就不重复询问
  local room = player.room
  local mainSkill = skill.main_skill or skill
  -- 临时增加技能，通过hasSkill检测
  local ret = false
  room:handleAddLoseSkills(player, mainSkill.name, skel.name, false, true)
  if skill:triggerable(event, target, player, data) then
    ret = true
  end
  room:handleAddLoseSkills(player, "-" .. mainSkill.name, skel.name, false, true)
  return ret
end

---@param skill TriggerSkill
local function triggerEquip(skill, event, target, player, data)
  --  skill:trigger(event, target, player, data)
  local room = player.room ---@type Room
  room.current_cost_skill = skill
  local ret
  if skill.cost == TriggerSkill.cost then
    -- 默认cost，则直接返回true
    -- 为了不让朱雀扇、寒冰箭二次询问。青釭剑和古锭刀这种锁定技倒是不会问两次
    ret = true
  else
    ret = skill:cost(event, target, player, data)
  end

  room.current_cost_skill = nil

  local cost_data_bak = event:getCostData(skill)
  room.logic:trigger(fk.BeforeTriggerSkillUse, player, { skill = skill, willUse = ret })

  -- 贯石斧，青龙刀还得赋值cost_data
  if ret then
    local skill_data = {cost_data = cost_data_bak, tos = {}, cards = {}}
    if cost_data_bak and type(cost_data_bak) == "table" then
      skill_data.tos = cost_data_bak.tos
      skill_data.cards = cost_data_bak.cards
    end
    room:useSkill(player, skill, function()
      return skill:use(event, target, player, data)
    end, skill_data)
  end
end

for _, equip_event in ipairs(all_events) do
  skel:addEffect(equip_event, {
    priority = 0.1, -- 装备优先级0.1
    can_trigger = function (self, event, target, player, data)
      if not player:hasSkill(skel.name) or player:isNude() then return end
      local skills = getSkillsForEvent(event)
      for _, skill in ipairs(skills) do
        local equip = skill:getSkeleton().attached_equip
        if equip and #getMatchCard(player, equip) > 0 then
          if checkTriggerable(skill, event, target, player, data) then
            return true
          end
        end
      end
    end,
    on_trigger = function (self, event, target, player, data)
      local skills = getSkillsForEvent(event)
      for _, skill in ipairs(skills) do
        if not player:hasSkill(skel.name) then break end
        local equip = skill:getSkeleton().attached_equip
        if equip and #getMatchCard(player, equip) > 0 then
          if checkTriggerable(skill, event, target, player, data) then
            event:setCostData(self, { equip = equip, skill = skill })
            self:doCost(event, target, player, data)
          end
        end
      end
    end,
    on_cost = function (self, event, target, player, data)
      local cost_data = event:getCostData(self)
      if not cost_data then return end
      local equip = cost_data.equip
      local ids = getMatchCard(player, equip)
      local chosen = player.room:askToCards(player, {
        min_num = 1, max_num = 1, skill_name = skel.name, include_equip = true,
        pattern = tostring(Exppattern{ id = ids }),
        prompt = "#emo__qicui-invoke:::" .. equip
      })
      if #chosen > 0 then
        cost_data.cards = chosen
        event:setCostData(self, cost_data)
        return true
      end
    end,
    ---@param player ServerPlayer
    on_use = function (self, event, target, player, data)
      local room = player.room
      local cost_data = event:getCostData(self)
      if not cost_data then return end
      local cards = cost_data.cards
      if not cards or #cards == 0 then return end
      local notSlash = Fk:getCardById(cards[1]).trueName ~= "slash"
      room:recastCard(cost_data.cards, player, skel.name)
      if player.dead then return end
      local skill = cost_data.skill ---@type TriggerSkill
      -- 这一步直接进入doCost了，不用判断hasSkill
      triggerEquip(skill, event, target, player, data)
      if notSlash then
        moveInBoard(player)
      end
    end,
  })
end

--- 记录所有可以发动的技能，减少计算量
skel:addAcquireEffect(function (self, player, is_start)
  local room = player.room
  local trigger, viewas, active = {}, {}, {}
  for _, name in ipairs(Fk:getAllCardNames("e")) do
    local card = Fk:cloneCard(name)
    if card.type == Card.TypeEquip then
      ---@cast card EquipCard
      local skill = card.equip_skill -- 装备技能，类型是Skill
      if skill then
        if skill:isInstanceOf(TriggerSkill) then
          table.insert(trigger, skill)
        elseif skill:isInstanceOf(ViewAsSkill)  then
          table.insert(viewas, skill.name)
        elseif skill:isInstanceOf(ActiveSkill) then
          table.insert(active, skill.name)
        end
      end
    end
  end
  -- 用于记录每个时机可发动的装备触发技
  local trigger_map = table.map(all_events, function ()
    return {}
  end)
  for _, skill in ipairs(trigger) do
    local all_skills = table.filter(table.connect({skill}, skill.related_skills), function (s) ---@type TriggerSkill[]
      return s:isInstanceOf(TriggerSkill) and not s.is_delay_effect
    end)
    for _, s in ipairs(all_skills) do
      local index = table.indexOf(all_events, s.event)
      if index > 0 then
        table.insert(trigger_map[index], s.name)
      end
    end
  end
  room:setBanner("emo__qicui_trigger", trigger_map)
  room:setBanner("emo__qicui_viewas", viewas)
  room:setBanner("emo__qicui_active", active)
end)

return skel
